/**
 * FH Technikum-Wien,
 *
 * Alcatraz - Remote - Projekt
 * Group B5
 *
 * @author Andreas Schmid
 * @author Roman Leonhartsberger
 * @author Bernhard Höchtl
 * @author Christian Pipp
 *
 * @date 2011/04/22
 * @version 1.0
 *
 **/

package alcatraz.server;

import alcatraz.common.IAlcatrazServer;
import alcatraz.common.IAlcatraz;
import alcatraz.common.AlcatrazException;
import alcatraz.common.PlayerData;
import java.rmi.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import spread.AdvancedMessageListener;
import spread.MembershipInfo;
import spread.SpreadConnection;
import spread.SpreadException;
import spread.SpreadGroup;
import spread.SpreadMessage;
import java.net.UnknownHostException;
import java.rmi.server.UnicastRemoteObject;
import java.net.InetAddress;
import java.util.*;

public class AlcatrazServerImpl extends UnicastRemoteObject implements IAlcatrazServer,AdvancedMessageListener,IAlcatraz {

  SpreadConnection conn;
  Game currentGame = null;
  private Boolean isMaster = null;


  /**
   * public Konstruktur um das Spread Service zu starten
   * und um ein neues Game Objekt zu instanzieren
   * @param host
   * @throws RemoteException
   * @throws UnknownHostException
   */
  public AlcatrazServerImpl(String host) throws RemoteException, UnknownHostException
  {
      System.out.println("generate Game Object...");
      currentGame = new Game();
      System.out.println("Starting Spread Service...");
      this.startSpreadService(host);
  }

  /**
   * Innerhalb dieser Methode wird die Spread Connection zum Spread Dämon aufgebaut
   * Dafür ist es erforderlich, dass dieser Dämon auch gestartet ist und die IP
   * der Rechner, die miteinander verbunden sind im sich im selben Segement befinden
   * (festzulegen in der spread.conf)
   * @param host
   * @return TRUE wenn Anmeldung bei Spread erfolgreich
   */
  private Boolean startSpreadService(String host)
  {
     conn = new SpreadConnection();     
        try  {
         conn.connect(InetAddress.getByName(host), 0, "testing", false, false);         
        } catch (UnknownHostException ex) {
          Logger.getLogger(AlcatrazServerImpl.class.getName()).log(Level.SEVERE, null, ex);
          return false;
        } catch (SpreadException ex) {
          Logger.getLogger(AlcatrazServerImpl.class.getName()).log(Level.SEVERE, null, ex);
          return false;
        }
     conn.add(this);

     return true;
  }

   /**
   * Methode um einer bestimmten Spread Gruppe beizutreten
   * @param SpreadGroupName
   */
  void joinSpreadGroup(String SpreadGroupName)
  {
      SpreadGroup group = new SpreadGroup();

      try {
            System.out.println("Joining Spread group: " + SpreadGroupName);
            group.join(conn, SpreadGroupName);
        } catch (SpreadException ex) {
            Logger.getLogger(AlcatrazServerImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
  }

  /**
   * Hier kommen die Messages über den AdvancedMessageListener an
   * @param message
   */
  public void membershipMessageReceived(SpreadMessage message) {
     MembershipInfo memberinfo = message.getMembershipInfo();
     SpreadGroup members[] = memberinfo.getMembers();

     System.out.println("Membership Message received: " +  message.toString()) ;

     if(memberinfo.isRegularMembership())   {
         if(memberinfo.isCausedByJoin())    {
             System.out.println("Neues Mitglied in der Spread Gruppe");
             /* Wenn es nur ein Member gibt in der Gruppe wird dieser automatische zu Maser */
            if(members.length == 1) {
                isMaster = true;
            }
         }
     }     
  }

  public void syncServer()    {
       if (this.conn != null)
        {
            try
            {
                String data = "";
                short type = 0;
                SpreadMessage message = new SpreadMessage();
                message.setObject(data);
                message.addGroup(SpreadGroupName);
                message.setReliable();
                message.setSelfDiscard(true);
                message.setType(type);
                this.conn.multicast(message);
            }
            catch (SpreadException ex)
            {
                Logger.getLogger(AlcatrazServerImpl.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
  }

  /**
   * Message die über Spread außerhalb der Gruppe verschickt werden
   * @TODO: Was wollen wir hier genau machen?
   * @param message
   */
  public void regularMessageReceived(SpreadMessage message)  {
     System.out.println("Regular Message received: " +  message.toString()) ;
  }


  /**
   * Player wird dem Game Objekt zugeordnet
   * @param player
   * @throws AlcatrazException
   * @throws RemoteException
   */
  public void register(PlayerData player) throws AlcatrazException, RemoteException
  {
      currentGame.addPlayer(player);
  }

  /**
   * Player wird aus dem Game Objekt gelöscht
   * @param player
   * @throws RemoteException
   */
  public void unregister(PlayerData player) throws RemoteException
  {
    currentGame.removePlayer(player);
  }

  /**
   *
   * @param player
   * @throws AlcatrazException
   * @throws RemoteException
   */
  public void setName(PlayerData player, String newNameOfPlayer) throws AlcatrazException, RemoteException
  {
    currentGame.setName(player, newNameOfPlayer);
  }

  /**
   * @TODO: wozu brauchen wir das nochmal?
   * @param isReady
   * @throws AlcatrazException
   * @throws RemoteException
   */
  public void setReady(PlayerData player) throws AlcatrazException, RemoteException
  {
    System.out.println("Method setReady...");
  }

  /**
   * Liefert die aktuelle Spielerliste des Game Objets
   *
   * @return ArrayList of PlayerData
   * @throws AlcatrazException
   * @throws RemoteException
   */
  public <PlayerData>ArrayList getPlayers() throws AlcatrazException, RemoteException
  {
    return currentGame.getPlayers();
  }

  /**
   * Startet das Spiel
   * 
   * @throws AlcatrazException
   * @throws RemoteException
   */
   public void startGame (PlayerData player) throws AlcatrazException, RemoteException {
     
   }
}

